{$X-}   {Turn off stack expansion. This is a Lisa concept, not needed on Mac}
{$U-}   {Turn off the Lisa Libraries. This is required by the WorkShop}
{$R-}   {Turn off range checking}
{$L-}
Program Windows;

{  Jeffery J. Bradford  Macintosh Technical Support  April 1985  }

{This example will help you become familiar with how windows work}
{in conjunction with the Event Manager. Recommened reading for   }
{better understanding of this example is the Window Manager and  }
{the Event Manager                                               }

{ This particular example deals with windows and uses calls that }
{ that pertain only to windows and operations involving window   }
{ manipulation. It creates 2 windows by different methods. It    }
{ demonstrates how to activate, deactivate, grow, shrink, put-   }
{ away, bring back, and update a window.}


USES
    {$U Obj/Memtypes  } MemTypes,
    {$U Obj/QuickDraw } QuickDraw,
    {$U Obj/OSIntf    } OSIntf,
    {$U Obj/ToolIntf  } ToolIntf,
    {$U Obj/PackIntf  } PackIntf,
    {$U Obj/MacPrint  } MacPrint;

CONST
{menu stuff}
    AppleMenu = 256;
    FileMenu  = 257;
    EditMenu  = 258;

{window IDs}
    WindResID = 256;


TYPE
{this is useful stuff you might need sometime}

    WordStuff = Packed Record
       Case Integer of
         0: (word: Integer);
         1: (chr1,chr0: Char);
         2: (SByte1,SByte0: SignedByte);
         3: (b15,b14,b13,b12,b11,b10,b9,b8,b7,b6,b5,b4,b3,b2,b1,b0: Boolean)
       End;

    CharStuff = Packed Record
         chr3,chr2,chr1,chr0: char;
       End;

    LMWordPtr = ^Integer;          {pointer to low memory address}
    LMLongPtr = ^LongInt;          {pointer to low memory address - long}



VAR
{global program stuff}
    Finished:      Boolean;    {used to terminate the program}
    ClockCursor:   CursHandle; {handle to the waiting watch cursor}

{Screen stuff}
    DragArea:   Rect;          {holds the area where window can be dragged in}
    GrowArea:   Rect;          {holds the area to which a window's size can change}
    Screen:     Rect;          {holds the screen dimensions}

{Window stuff}
    OneWindow:   WindowPtr;    {pointer to the first window}
    TwoWindow:   WindowPtr;    {pointer to the second window}

{-----------------------------------------------------------------------------
                     end of global variable definition
-----------------------------------------------------------------------------}

 PROCEDURE Update_Scroll_Bar_Areas(ofTheWindow:WindowPtr);
 Var BarArea: Rect;

 Begin
 {invalidate the right scroll bar area first}
   BarArea := ofTheWindow^.portRect; {makes the BarArea have window coordinates}
   BarArea.left := BarArea.right-16; {move left in so its only the Scroll Bar Area}
   InvalRect(BarArea);  {invalidate this portion of the window}

 {invalidate the bottom scroll bar area next }
   BarArea := ofTheWindow^.portRect; {reset BarArea to window coordinates}
   BarArea.top := BarArea.bottom-16; {move top down so its only the botton bar}
   InvalRect(BarArea);

   {NOTE: is your drawing is fast just Invalidate the entire PortRect}
 End;

{-----------------------------------------------------------------------------}

 PROCEDURE ReSizeWindow(theWindow:WindowPtr; MouseLoc: Point);

 Var NewSize: LongInt;
     Width:   Integer;
     Height:  Integer;

 Begin
   NewSize := GrowWindow(theWindow,      { grow this window}
                         MouseLoc,       { mouse location  }
                         GrowArea);      { limits of growth - global var}
   If NewSize <> 0 then
   begin
     Height :=  HiWord(NewSize);         {high word of..}
     Width  :=  LoWord(NewSize);         {low word of...}

     Update_Scroll_Bar_Areas(theWindow); {erase where the scroll bars WERE}

     If Height< 16 then Height := 16; {don't let the window close on itself}
     If Width < 16 then Width  := 16;

{now set the new size}
     SizeWindow(theWindow,   {resize this Window}
                    Width,   {set the width}
                   Height,   {set the height}
                    TRUE);   {set the update flag}

     Update_Scroll_Bar_Areas(theWindow);  {redraw where the scroll bars ARE now }

   end; {if size of window was changed}
 End;

{-------------------------------------------------------------------}

PROCEDURE ProcessMenu_in(CodeWord:longint);
Var
  Menu_No:    integer;        {menu number that was selected}
  Item_No:    integer;        {item in menu that was selected}
  NameHolder: Str255;         {name holder for desk accessory or font}
  DNA:        integer;        {OpenDA will never return 0, so don't care}

Begin
  If CodeWord <> 0 then {go ahead and process the command}
  begin
    Menu_No := HiWord(CodeWord);   {get the Hi word of...}
    Item_no := LoWord(CodeWord);   {get the Lo word of...}

    Case Menu_No of

     AppleMenu: Begin
                  GetItem(GetMHandle(AppleMenu), Item_No, NameHolder);
                  DNA := OpenDeskAcc(NameHolder);
                End;

      FileMenu: Begin
                  Case Item_No of
                    1: Finished := True;          {quit}
                  End;
                End;

      EditMenu: Begin
                  If Not SystemEdit(Item_no - 1) {if not for a desk accessory}
                  then
                    Case Item_No of
                      1: begin end;               {undo}
                    { 2:                           line divider}
                      3: begin end;               {cut}
                      4: begin end;               {copy}
                      5: begin end;               {paste}
                      6: begin end;               {clear}
                    End;
                End;

    End;{case of Menu_No}

    HiliteMenu(0);               {unhilite after processing menu}
  end; {the If codeword <> 0}
End; {of ProcessMenu_in procedure}


{-------------------------------------------------------------------}
{----- These are procedures called from the main event loop  -------}

PROCEDURE DealwthMouseDowns(Event:EventRecord);
Var Location: integer;
    WindowPointedTo: WindowPtr;
    MouseLoc:Point;
    WindoLoc:integer;
Begin
  MouseLoc := Event.Where;
  WindoLoc := FindWindow(MouseLoc, WindowPointedTo);
  Case WindoLoc of

     inMenuBar: ProcessMenu_in(MenuSelect(MouseLoc));

     inSysWindow: SystemClick(Event,WindowPointedTo);

     inContent: If WindowPointedTo <> FrontWindow
                then SelectWindow(WindowPointedTo)
                else begin {do something} end;

     inGrow:    If WindowPointedTo <> FrontWindow
                then SelectWindow(WindowPointedTo)
                else ReSizeWindow(WindowPointedTo,MouseLoc);

     inDrag   :DragWindow(WindowPointedTo,MouseLoc,DragArea);

     inGoAway :If TrackGoAway(WindowPointedTo,MouseLoc)
               then DisposeWindow(WindowPointedTo); {since W mgr allocated space}

  End{ of case};
End;

{-----------------------------------------------------------------------------}

PROCEDURE DealwthKeyDowns(Event:EventRecord);
Var CharCode:  char;
Begin

  CharCode:= CharStuff(Event.message).Chr0; {get low byte w/no processing}

  If BitAnd(Event.modifier,CmdKey) = CmdKey
   then
     begin  {key board command - probably a menu command}
       ProcessMenu_in(MenuKey(CharCode));
     end
   else
     begin  {regular keyboard entry}
       {TEKey(CharCode,TextHandle); if we had a text edit record}
       {Scrolltext}
     end;
End;

{-----------------------------------------------------------------------------}

PROCEDURE DealwthActivates(Event: EventRecord);
Var TargetWindow:WindowPtr;
Begin
   TargetWindow := WindowPtr(Event.message);
   DrawGrowIcon(TargetWindow);

   If Odd(Event.modifiers) {then the window is becoming active}
   then
     begin
       SetPort(TargetWindow);
       {and activate whatever else you need}
       {the scroll bars}
       {hilite selected text}
     end
   else
     begin
       {deactivate whatever you need}
       {deactivate the scroll bars}
       {UNhilite selected text}
     end;
End;

{-----------------------------------------------------------------------------}

PROCEDURE DealwthUpdates(Event:EventRecord);
Var UpDateWindow,
          TempPort: WindowPtr;
Begin
   UpDateWindow := WindowPtr(Event.message);
   GetPort(TempPort);                {Save the current port}

   SetPort    (UpDateWindow);      {set the port to one in Evt.msg}
   BeginUpDate(UpDateWindow);
     EraseRect(UpDateWindow^.portRect);
(*     or
     EraseRect(UpDateWindow^.VisRgn^^.rgnBBox); *)
     DrawGrowIcon(UpDateWindow);
   EndUpDate  (UpDateWindow);

   SetPort    (TempPort);             {restore to the previous port}
End;

{-----------------------------------------------------------------------------}

PROCEDURE MainEventLoop;
Var Event:EventRecord;
    ProcessIt: Boolean;
Begin
  Repeat
    SystemTask;             {so you can support Desk Accessories}

    ProcessIt := GetNextEvent(EveryEvent,Event);
    If ProcessIt{is true} then {we'll ProcessIt}
          Case Event.what of

            mouseDown  : DealwthMouseDowns(Event);
            KeyDown    : DealwthKeyDowns  (Event);
            ActivateEvt: DealwthActivates (Event);
            UpDateEvt  : DealwthUpdates   (Event);

          End;{of Case}
  Until Finished; {terminate the program}
End;

{-----------------------------------------------------------------------------}

PROCEDURE InitThings;
Begin
  InitGraf(@thePort);          {create a grafport for the screen}

  MoreMasters;                 {extra pointer blocks at the bottom of the heap}
  MoreMasters;                 {this is 5 X 64 master pointers}
  MoreMasters;
  MoreMasters;
  MoreMasters;

{get the cursors we use and lock them down - no clutter}
  ClockCursor := GetCursor(watchCursor);
  HLock(Handle(ClockCursor));

{show the watch while we wait for inits & setups to finish}
  SetCursor(ClockCursor^^);

{init everything in case the app is the Startup App}
  InitFonts;                     {startup the fonts manager}
  InitWindows;                   {startup the window manager}
  InitMenus;                     {startup the menu manager}
  TEInit;                        {startup the text edit manager}
  InitDialogs(Nil);              {startup the dialog manager}

  Finished := False;             {set program terminator to false}
  FlushEvents(everyEvent,0);     {clear events from previous program}
End;

{-----------------------------------------------------------------------------}

PROCEDURE SetupLimits;
Begin
  Screen := ScreenBits.Bounds;   {set the size of the screen}
  SetRect(DragArea,Screen.left+4,Screen.top+24,Screen.right-4,Screen.bottom-4);
  SetRect(GrowArea,Screen.left,Screen.top+24,Screen.right,Screen.bottom);
End;

{-----------------------------------------------------------------------------}

PROCEDURE SetupMenus;
Var
  MenuTopic: MenuHandle;
Begin
  MenuTopic := GetMenu(AppleMenu);  {get the apple desk accessories menu}
  AddResMenu(MenuTopic,'DRVR');     {adds all names into item list}
  InsertMenu(MenuTopic,0);          {put in list held by menu manager}

  MenuTopic := GetMenu(FileMenu);   {always need this for Quiting}
  InsertMenu(MenuTopic,0);

  MenuTopic := GetMenu(EditMenu);   {always need for editing Desk Accessories}
  InsertMenu(MenuTopic,0);

  DrawMenuBar;           {all done so show the menu bar}
End;

{-----------------------------------------------------------------------------}

PROCEDURE SetupWindows;
Var  WRect:    Rect;
     Typ_ofW1: integer;
     Visible:  boolean;
     GoAway:   boolean;
     RefVal:   LongInt;

Begin
{ Create the first window using the NewWindow Command }

  SetRect(WRect,10,40,230,150);  {set the size of the window -global coordinates}
  Typ_ofW1 := 16;                {set window type - rounded corner   }
  Visible := true;               {set the window to visible in its plane}
  GoAway := true;                {give the window a GoAway box }

  OneWindow := NewWindow(Nil,           { Window Mgr will allocate space in Heap}
                         WRect,         { rectangle with windows size}
                         'Window 1',    { the title of the window }
                         Visible,       { set the window to visible in its plane}
                         Typ_ofW1,      { Window definition ID}
                         Nil,           { behind ptr: window is set to last}
                         GoAway,        { draw a goaway region in title area }
                         RefVal);       { 32-bit value that can be used by App}


{ Create the second window from information stored on the Resource file }

  TwoWindow := GetNewWindow(WindResID,      {Resource ID where Window info is }
                            NIL,            {W Mgr allocates space for W. Record}
                            POINTER(-1));   {set the window to be in front    }

{NOTE: NewWindow and GetNewWindow have initiated an ActivatEvt and an }
{      UpDateEvt event. They are being queued up by the event manager.}
{      Also, the window record is Non-relocatable, so put it on the stack}
{      or create it so that it is low in the heap space, reduce fragmentation}
End;

{-----------------------------------------------------------------------------}

PROCEDURE SetUpThings;
Begin
  SetupWindows;         {do first so its low in heap}
  SetupMenus;
  SetupLimits;

  InitCursor;           {ready to go, so show the Arrow cursor}
End;

{-----------------------------------------------------------------------------}

PROCEDURE CloseThings;
Begin
{close files, if you changed sys resources, UNchange them here be carefull}
{about changing sys things, remember the Switcher could be around}
End;

{-----------------------------------------------------------------------------}

BEGIN
  InitThings;
  SetUpThings;
  MainEventLoop;
  CloseThings;
END.
